%% Author: vivimice
%% Created: Jan 9, 2012
%% Description: buffered output module
-module(tio_sender).

-define(BUFFER_SIZE, 512).

%%
%% Include files
%%
-include("telnet.hrl").

%%
%% Exported Functions
%%
-export([start/1, stop/1, init/1, loop/2, write_bytes/2, write_bytes_nb/2, flush/1,
		 send_telnet_option/3, send_telnet_suboption/3]).

%%
%% API Functions
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% FSM
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

start(Socket) ->
	Sender = spawn_link(?MODULE, init, [Socket]),
	Sender.

init(Socket) ->
	?MODULE:loop(Socket, <<>>).

loop(Socket, Buffer) ->
	receive
		
		{write, BinaryData, nobuf} ->
			NewBuffer = <<Buffer/binary, BinaryData/binary>>,
			flush_i(Socket, NewBuffer),
			?MODULE:loop(Socket, <<>>);
		
		{write, BinaryData} ->
			NewBuffer = <<Buffer/binary, BinaryData/binary>>,
			NewBufferSize = byte_size(NewBuffer),
			if 
				NewBufferSize >= ?BUFFER_SIZE ->
					flush_i(Socket, NewBuffer),
					?MODULE:loop(Socket, <<>>);
				true ->
					?MODULE:loop(Socket, NewBuffer)
			end;
		
		flush ->
			flush_i(Socket, Buffer),
			?MODULE:loop(Socket, <<>>);
		
		stop ->
			gen_tcp:close(Socket)
	end.

flush_i(_Socket, <<>>) ->
	ok;
flush_i(Socket, Buffer) ->
	case gen_tcp:send(Socket, Buffer) of
		ok ->
			ok;
		{error, Reason} ->
			logger:error("Failed sending data. Reason: ~p", [Reason])
	end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

stop(Sender) ->
	Sender ! stop.

flush(Sender) ->
	Sender ! flush.

send_telnet_option(Sender, Command, Option) ->
	write_bytes_nb(Sender, <<?IAC, Command, Option>>).

send_telnet_suboption(Sender, Option, SubOptionBin) 
  when is_number(Option), is_binary(SubOptionBin) ->
	write_bytes_nb(Sender, <<?IAC, ?SB, Option, SubOptionBin/binary, ?IAC, ?SE>>).

write_bytes(Sender, Binaries) when is_binary(Binaries) ->
	Sender ! {write, Binaries}.

write_bytes_nb(Sender, Binaries) when is_binary(Binaries) ->
	Sender ! {write, Binaries, nobuf}.
